package edu.cmu.cs211.chess.unittested;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import edu.cmu.cs211.chess.board.ArrayBoard;
import edu.cmu.cs211.chess.board.Board;
import edu.cmu.cs211.chess.board.Move;
import edu.cmu.cs211.chess.search.AbstractSearcher;

/**
 * An implementation of Alpha Beta search.
 * 
 * This is the class that will be unit tested by FrontDesk.
 */
public class TestedAlphaBetaFixedDepth<M extends Move<M>, B extends Board<M, B>>
		extends AbstractSearcher<M, B> {
	private TestedEvaluator te = new TestedEvaluator();
	private M optMove;
	private int score = -(te.infty());

	public M getBestMove(B board, int myTime, int opTime) {
		int depth = 0;
		int alpha = -(te.infty());
		int beta = te.infty();
		List<M> mList = board.generateMoves();
		M am = null;

		for (Iterator<M> it = mList.iterator(); it.hasNext();) {
			am = it.next();
			board.applyMove(am);
			score = -negamax(board, -beta, -alpha, depth + 1);
			board.undoMove();
			if (score > alpha) {
				optMove = am;
				alpha = score;
			}
		}
		return optMove;
	}
	
	/*
	 * Alpha-beta Negamax bounded search
	 */
	private int negamax(B ab, int a, int b, int d) {

		List<M> ml = ab.generateMoves();
		M am;
		//checkmate
		if (ab.inCheck() && ml.isEmpty())
			return -(te.mate());
		//stalemate
		if (!ab.inCheck() && ml.isEmpty())
			return te.stalemate();

		if (d == super.maxDepth)
			return te.eval((ArrayBoard) ab);
		else if (d < super.maxDepth) {
			if(ab.getRepTable().lookup(ab)==2)
				return 0;
			ab.getRepTable().delta(ab, 1);
			for (Iterator<M> it = ml.iterator(); it.hasNext();) {
				am = it.next();
				ab.applyMove(am);
				int temp = -1 * negamax(ab, -b, -a, d + 1);
				a = max(a, temp);
				ab.undoMove();
				if (a >= b) {
					return a;
				}
			}
		}
		ab.getRepTable().delta(ab, -1);
		return a;
	}

	private int max(int a, int b) {
		return (a < b) ? b : a;
	}
}
